using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DragonAwakening.Core;
using DragonAwakening.Core.Graphics;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using DragonAwakening.Core.Game;

namespace DragonAwakening.Core.Game
{
    /// <summary>
    /// Character view.
    /// </summary>
    public class CharacterView : IScreenView<IEnumerable<Character>>, IClickTarget
    {
        /// <summary>
        /// Character data size.
        /// </summary>
        private const int CharacterInfoSize = 120;

        /// <summary>
        /// Height of the bar.
        /// </summary>
        private const int BarHeight = 90;

        /// <summary>
        /// Font
        /// </summary>
        private SpriteFont font;

        /// <summary>
        /// Health bar texture.
        /// </summary>
        private Texture2D healthBarTexture;

        /// <summary>
        /// Health bar texture.
        /// </summary>
        private Texture2D staminaBarTexture;

        /// <summary>
        /// Health bar texture.
        /// </summary>
        private Texture2D manaBarTexture;

        /// <summary>
        /// Dead character texture.
        /// </summary>
        private Texture2D skullTexture;

        /// <summary>
        /// Selected character frame texture.
        /// </summary>
        private Texture2D characterFrameTexture;

        /// <summary>
        /// Texture manager.
        /// </summary>
        private ITextureManager textureManager;

        /// <summary>
        /// Game context.
        /// </summary>
        private IGameContext context;

        /// <summary>
        /// Hero tiles click rectangles.
        /// </summary>
        private Rectangle[] heroRects = new[] {
            new Rectangle(40, 20, 80, 80), 
            new Rectangle(40, 140, 80, 80),
            new Rectangle(40, 260, 80, 80),
            new Rectangle(40, 380, 80, 80)
        };

        /// <summary>
        /// Constructs the character view.
        /// </summary>
        public CharacterView(SpriteFont font, ITextureManager textureManager, IGameContext context)
        {
            font.RequiredNotNull("font");
            textureManager.RequiredNotNull("textureManager");
            context.RequiredNotNull("context");

            this.font = font;
            this.textureManager = textureManager;
            this.context = context;

            this.healthBarTexture = textureManager.GetColorTexture(Color.Red);
            this.staminaBarTexture = textureManager.GetColorTexture(Color.Yellow);
            this.manaBarTexture = textureManager.GetColorTexture(Color.Blue);

            this.skullTexture = textureManager.Get("skull");
            this.characterFrameTexture = this.textureManager.Get("character_frame");
        }

        /// <summary>
        /// Draws the character.
        /// </summary>
        /// <param name="data">Character data.</param>
        public void Draw(IViewPort view, IEnumerable<Character> characterList)
        {
            Vector2 position = new Vector2(3, 5);
            Character selectedCharacter = this.context.CurrentState.Is<CharacterStatsGameState>() 
                ? ((CharacterStatsGameState)this.context.CurrentState).Character 
                : null;

            foreach (var character in characterList)
            {
                Vector2 namePosition = new Vector2(position.X, position.Y - 5);
                view.DrawString(this.font, character.Name, namePosition, Color.White);

                var facePosition = position + new Vector2(40, 20);
                
                if (character == selectedCharacter)
                {
                    var faceFrame = new Rectangle((int)facePosition.X - 3, (int)facePosition.Y, 84, 80);
                    view.Draw(this.characterFrameTexture, faceFrame, Color.White, 0.8F);
                }

                var faceTexture = this.GetFaceTexture(character);
                view.Draw(faceTexture, facePosition, Color.White, 0.9F);

                position += new Vector2(0, 20);

                this.DrawBar(view, position, character.Health, 1, this.healthBarTexture);
                this.DrawBar(view, position, character.Stamina, 12, this.staminaBarTexture);
                this.DrawBar(view, position, character.Mana, 23, this.manaBarTexture);

                if (!character.IsAlive)
                {
                    view.Draw(this.skullTexture, facePosition + new Vector2(40, 40), Color.White);
                }

                position += new Vector2(0, CharacterInfoSize - 20);
            }
        }

        /// <summary>
        /// Gets the texture for the character race.
        /// </summary>
        private Texture2D GetFaceTexture(Character character)
        {
            string textureName = string.Format("character_head_{0}_{1}", character.Race.RaceName.ToString().ToLower(), character.Sex.ToString().ToLower());
            return this.textureManager.Get(textureName);
        }

        /// <summary>
        /// Draws the bar.
        /// </summary>
        private void DrawBar(IViewPort view, Vector2 position, MaxValueData data, int offset, Texture2D texture)
        {
            var percent = (int)(data.Percentage * BarHeight);
            var rect = new Rectangle((int)position.X + offset, (int)position.Y + BarHeight - percent, 10, percent);
            view.Draw(texture, rect, Color.White);
        }

        /// <summary>
        /// Process on click event
        /// </summary>
        public bool OnClick(Point click, IGameContext context)
        {
            int groupCount = context.Group.Count;
            for (int index = 0; index < groupCount; index++)
            {
                if (this.heroRects[index].Contains(click))
                {
                    var clickedCharacter = context.Group[index];
                    if (context.CurrentState.Is<CharacterStatsGameState>() && ((CharacterStatsGameState)context.CurrentState).Character == clickedCharacter)
                    {
                        context.SetState(GameState.Instance);
                    }
                    else
                    {
                        var state = CharacterStatsGameState.Instance;
                        state.Mode = CharacterInfoMode.Bags;
                        state.Character = context.Group[index];
                        context.SetState(state);
                    }

                    return true;
                }
            }

            return false;
        }
    }
}
